package com.hao.model;

import com.hao.dispatcher.Dispatcher;
import com.hao.dispatcher.PriorityFirstDispatcher;
import com.hao.dispatcher.SPNDispatcher;
import lombok.Data;

/**
 * PC模型。模拟整个系统环境，起到组合类功能的
 */
@Data
public class Computer {
    private Dispatcher dispatcher = null;//调度器

    private final QueueManager queueManager = new QueueManager();//内存

    private PCBProcess runningPCBProcess = null;//正在执行的进程。作为系统内部动态使用。

    private PCBProcess latestRunningPCBProcess = null;//最近一次运行的进程。作为一个记录，呈现给外部看。实际上并不用，由于程序是静态模拟故设置这么一个变量记录

    private  int systemTime = 0;//系统时间

    public Computer(Dispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }

    public void setDispatcher(Dispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }

    /**
     * 执行调度。
     * @return
     */
    private void doDispatcher() {
        runningPCBProcess = dispatcher.doDispatcher(queueManager);
        if (runningPCBProcess == null) {
            return;
        }
        runningPCBProcess.setStatus(2);//2运行
    }

    /**
     * 执行一次时间片。
     */
    public void execute() {
        //如果 抢占 或者 当前运行程序为空,每次执行前都要调度。
        //非抢占则仍然执行上一次的结果。
        if (!(dispatcher instanceof SPNDispatcher) || runningPCBProcess == null) {
            latestRunningPCBProcess = null;//重新调度，就重新记录
            //如果上一次运行完，还存活，则加入就绪队列
            if (runningPCBProcess != null) {
                runningPCBProcess.setStatus(0);
                queueManager.getReadyQueue().offer(runningPCBProcess);
                runningPCBProcess = null;
            }
            //重新调度
            doDispatcher();
            //如果调度的结果为空
            if (runningPCBProcess == null) {
                return;
            }
        }

        //执行前记录
        latestRunningPCBProcess = new PCBProcess();
        latestRunningPCBProcess.setName(runningPCBProcess.getName());
        latestRunningPCBProcess.setPri(runningPCBProcess.getPri());
        latestRunningPCBProcess.setStatus(2);
        latestRunningPCBProcess.setTime(runningPCBProcess.getTime());

        //执行一次时间片
        runningPCBProcess.execute(1);
        if (dispatcher instanceof PriorityFirstDispatcher) {
            runningPCBProcess.cutPri();//如果是优先数，则优先数要减1
        }
        systemTime++;
        if (runningPCBProcess.getTime() <= 0) { //如果剩余时间结束，则当前运行进程踢出
            runningPCBProcess.setStatus(1);
            runningPCBProcess = null;
            return;
        }

    }

    /**
     * 向就绪队列中添加一个进程。
     * 成功返回新进程的引用。
     * 失败返回空值。
     */
    public PCBProcess createPCBProcess() {
        return queueManager.createProcess();
    }
}
